﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using FinanSoft.Utilities;
using FinanSoft.Entities;
using System.Xml;

namespace FinanSoft.BusinessLayer
{
    public class WebServiceController
    {
        private Hashtable _DataBasexUserTable;
        private bool _isError;
        private string _errorMessage;
        private static WebServiceController _instance;

        #region Singleton
        private WebServiceController()
        {
            _DataBasexUserTable = new Hashtable();
            _isError = false;
            _errorMessage = "";
        }
        

        /// <summary>
        /// Método para implementar el patrón de Singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static WebServiceController GetInstance()
        {
            if (_instance == null)
                _instance = new WebServiceController();
            return _instance;
        }
        #endregion

        #region Properties

        public string ErrorMessage
        {
            get { return _errorMessage; }
            set { _errorMessage = value; }
        }

        public bool IsError
        {
            get { return _isError; }
            set { _isError = value; }
        }
        #endregion

        /// <summary>
        /// Método que se encarga de llamar al sistema para poder autenticar al
        /// cliente que está ingresando en el sistema
        /// </summary>
        /// <param name="username">Nombre de usuario del cliente</param>
        /// <param name="password">Contraseña del cliente</param>
        /// <returns>Retorna la cuenta auxiliar asociada a ese cliente (como información)</returns>
        public AuxiliarAccount LogIn(string username, string password, string company, string sessionId)
        {
            // Consigo el nombre de la base de datos de acuerdo al nombre de compañia y seteo el app reader con ese nombre
            String dbName = this.GetDataBaseName(company);
            if (dbName == "")
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_DB_COMPANY;
                return null;
            }

            AppConfigReader.GetInstance().DataBaseName = dbName;

            // Intento loguearme con el cliente
            AuxiliarAccount aux = UserManager.GetInstance().LoginUserClient(username, password);
            if (aux != null)
            {
                if( !_DataBasexUserTable.ContainsKey(sessionId))
                    _DataBasexUserTable.Add(sessionId, dbName);
                return aux;
            }

            _isError = true;
            _errorMessage = UserManager.GetInstance().ErrorMessage;

            return aux;
        }

        /// <summary>
        /// Método que se encarga de llamar al sistema para poder autenticar al
        /// vendedor que está ingresando en el sistema
        /// </summary>
        /// <param name="username">Nombre de usuario del vendedor</param>
        /// <param name="password">Contraseña del vendedor</param>
        /// <returns>Indica si la autenticación fue exitosa</returns>
        public bool LogInSalesman(string username, string password, string company, string sessionId)
        {
            // Consigo el nombre de la base de datos de acuerdo al nombre de compañia y seteo el app reader con ese nombre
            String dbName = this.GetDataBaseName(company);
            if (dbName == "")
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_DB_COMPANY;
                return false;
            }

            AppConfigReader.GetInstance().DataBaseName = dbName;

            // Intento loguearme con el cliente
            if (UserManager.GetInstance().LoginSalesman(username, password))
            {
                if (!_DataBasexUserTable.ContainsKey(sessionId))
                    _DataBasexUserTable.Add(sessionId, dbName);
                return true;
            }

            _isError = true;
            _errorMessage = UserManager.GetInstance().ErrorMessage;
            return false;
        }


        /// <summary>
        /// Método que se encarga de obtener las monedas disponibles en el sistema
        /// </summary>
        /// <returns>Retorna la lista de Monedas</returns>
        public List<Currency> GetCurrencies(string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                List<Currency> currencies = MoneyManager.GetInstance().GetAddedCurrencies();
                if (currencies.Count == 0)
                {
                    _isError = true;
                    _errorMessage = MoneyManager.GetInstance().ErrorMessage;
                }
                currencies.Add(MoneyManager.GetInstance().SystemCurrency);
                currencies.Add(MoneyManager.GetInstance().LocalCurrency);
                return currencies;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }

        }

        /// <summary>
        /// Método que se encarga de obtener las bodegas registradas en el sistema
        /// </summary>
        /// <returns>Retorna la lista de objetos bodega</returns>
        public List<StoreRoom> GetStoreRooms(string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                List<StoreRoom> storeRooms = StoreRoomManager.GetInstance().GetStoreRooms();
                if (storeRooms == null)
                {
                    _isError = true;
                    _errorMessage = StoreRoomManager.GetInstance().ErrorMessage;
                }
                return storeRooms;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }
        }

        /// <summary>
        /// Método que se encarga de obtener todos los artículos que hay en el sistema
        /// además de su información: bodega en donde está, el stock disponible, etc...
        /// </summary>
        /// <returns></returns>
        public List<Item> GetItems(string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                List<Item> items = ItemManager.GetInstance().GetItems();
                if (items == null)
                {
                    _isError = true;
                    _errorMessage = ItemManager.GetInstance().ErrorMessage;
                }
                return items;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }
        }

        /// <summary>
        /// Método que se encaga de obtener el impuesto por defecto para un artículo
        /// </summary>
        /// <returns>Retorna un objeto Impuesto con su respectiva información</returns>
        public Tax GetDefaultTax(string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                Tax tax = ConfigurationManager.GetInstance().GetDefaultTax();
                if (tax == null)
                {
                    _isError = true;
                    _errorMessage = ConfigurationManager.GetInstance().ErrorMessage;
                }
                return tax;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }
        }

        /// <summary>
        /// Método que se encarga de guardar el pedido del cliente como una orden de venta de la empresa
        /// </summary>
        /// <param name="idAuxiliarAccount">Id de la cuenta auxiliar asociada al cliente que realiza el pedido</param>
        /// <param name="postingDate">Fecha de emisión del pedido</param>
        /// <param name="deliveryExpDate">Fecha de vencimiento dl pedido</param>
        /// <param name="idMoneda">Moneda en que se hizo el pedido</param>
        /// <param name="amountBeforeTax">Monto antes de impuesto</param>
        /// <param name="taxAmount">Monto de impuestos</param>
        /// <param name="totalAmount">Monto después de impuesto</param>
        /// <param name="details">Lista de artículos que van en el documento</param>
        /// <returns>Retorna si la operación tuvo éxito o no</returns>
        public bool SaveOrderDocument(int idAuxiliarAccount, DateTime postingDate, DateTime deliveryExpDate, int idMoneda, double amountBeforeTax, double taxAmount, double totalAmount, List<FinanSoft.Entities.DocDetail> details, string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                bool noErrorDB = BuySaleManager.GetInstance().SaveDocument(Constants.OV_ACCOUNTING_ENTRY, idAuxiliarAccount, postingDate, deliveryExpDate, idMoneda, FinanSoft.Utilities.Constants.INVALID_ID, amountBeforeTax, taxAmount, totalAmount, details);
                if (noErrorDB == false)
                {
                    _isError = true;
                    _errorMessage = BuySaleManager.GetInstance().ErrorMessage;
                }
                return noErrorDB;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return false;
            }
        }


        /// <summary>
        /// Método que se encarga de guardar el la lista de compras del cliente como una factura cliente
        /// </summary>
        /// <param name="idAuxiliarAccount">Id de la cuenta auxiliar asociada a la sucursal en la que se realiza la compra</param>
        /// <param name="postingDate">Fecha de emisión del pedido</param>
        /// <param name="deliveryExpDate">Fecha de vencimiento del pedido</param>
        /// <param name="idMoneda">Moneda en que se hizo el pedido</param>
        /// <param name="amountBeforeTax">Monto antes de impuesto</param>
        /// <param name="taxAmount">Monto de impuestos</param>
        /// <param name="totalAmount">Monto después de impuesto</param>
        /// <param name="details">Lista de artículos que van en el documento</param>
        /// <returns>Retorna si la operación tuvo éxito o no</returns>
        public bool SaveClienInvoiceDocument(Document doc, string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                bool noErrorDB = BuySaleManager.GetInstance().SaveDocument(doc);
                OpenDocument docAbierto = OpenDocumentManager.GetInstance().GetOpenDoc(doc.IdCuentaAuxiliar)[0];
                docAbierto.DocumentOwner = AuxiliaryAccountManager.GetInstance().GetAuxiliarAccount(doc.IdCuentaAuxiliar);
                List<OpenDocument> listDocs = new List<OpenDocument>();
                listDocs.Add(docAbierto);

                Account temp =CatalogManager.GetInstance().GetAccount(AuxiliaryAccountManager.GetInstance().GetAuxiliarAccount(doc.IdCuentaAuxiliar).Parent);
                noErrorDB &= PaymentManager.GetInstance().RealizePayment(listDocs, temp, Constants.IS_CLIENT_CODE);
                if (noErrorDB == false)
                {
                    _isError = true;
                    _errorMessage = BuySaleManager.GetInstance().ErrorMessage;
                }
                return noErrorDB;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return false;
            }
        }

        public Document PreviewClienInvoiceDocument(int idAuxiliarAccount, DateTime postingDate, DateTime deliveryExpDate, int idMoneda, double amountBeforeTax, double taxAmount, double totalAmount, List<FinanSoft.Entities.DocDetail> details, string sessionId)
        {

            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                Document docPreview = BuySaleManager.GetInstance().PreviewDocument(Constants.FC_ACCOUNTING_ENTRY, idAuxiliarAccount, postingDate, deliveryExpDate, idMoneda, FinanSoft.Utilities.Constants.INVALID_ID, amountBeforeTax, taxAmount, totalAmount, details);

                if (docPreview == null)
                {
                    _isError = true;
                    _errorMessage = BuySaleManager.GetInstance().ErrorMessage;
                }
                return docPreview;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }
        }

        /// <summary>
        /// Obtiene los reportes para las consultas de ventas del caso para rutas de venta (en móvil)
        /// </summary>
        /// <param name="auxId">Id de la cuenta auxiliar del cliente para el que se hace el reporte</param>
        /// <param name="itemId">Id del item para el que se puede tener reportes</param>
        /// <param name="sessionId">Identificador de mi sesión</param>
        /// <returns></returns>
        public SaleReport[] GetSaleReport(int auxId, int itemId, string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                SaleReport[] reports = SaleRouteReports.SaleRouteManager.GetInstance().GetSaleReport(auxId, itemId);
                if (reports == null)
                {
                    _isError = true;
                    _errorMessage = Constants.ERROR_REPORT_CONNECTION_FAILED;
                }
                return reports;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }
        }

        /// <summary>
        /// Obtiene todas las cuentas auxiliares que pertenecen a clientes
        /// </summary>
        /// <returns></returns>
        public AuxiliarAccount[] GetClients(string sessionId)
        {
            if (_DataBasexUserTable.ContainsKey(sessionId))
            {
                AppConfigReader.GetInstance().DataBaseName = (string)_DataBasexUserTable[sessionId];
                Hashtable auxiliarTable = AuxiliaryAccountManager.GetInstance().GetAuxiliarAccountsList();
                if (auxiliarTable == null)
                {
                    _isError = true;
                    _errorMessage = MoneyManager.GetInstance().ErrorMessage;
                }
                List<AuxiliarAccount> clients = new List<AuxiliarAccount>();
                foreach (AuxiliarAccount aux in auxiliarTable.Values)
                    if (aux.AccountType == Constants.AuxiliarAccountType.client)
                        clients.Add(aux);
                return clients.ToArray();
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NO_SESSIONID_VALID;
                return null;
            }

        }

        /// <summary>
        /// Método que se encarga de revisar en el xml de compañías el  nombre de la base de datos que le corresponde
        /// </summary>
        /// <param name="company">Nombre de la compañía</param>
        /// <returns>Nombre de la base de datos asociada</returns>
        private String GetDataBaseName(String company)
        {
            String dataBaseName = "";
            //Leer primero cual compañia se seleccionó para sacar la base de datos
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(Constants.DIRECTORY_COMPANIES);

            XmlNodeList Empresas = xDoc.GetElementsByTagName(Constants.TAG_COMPANIES);
            XmlNodeList compañia = ((XmlElement)Empresas[0]).GetElementsByTagName(Constants.TAG_COMPANY);
            foreach (XmlNode nodo in compañia)
            {
                if (nodo.Attributes.GetNamedItem(Constants.TAG_COMPANY_NAME).InnerText.Equals(company))
                    dataBaseName = nodo.Attributes.GetNamedItem(Constants.TAG_COMPANY_DATA_BASE).InnerText;
            }

            return dataBaseName;
        }
    }
}
